//------------------------------------------------------------------------------
// <copyright file="IJsonNode.h" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------

#pragma once

#include "JsonString.h"

namespace Microsoft { namespace Internal { namespace GamesTest { namespace Rpc { namespace Server
{
	/// <summary>
	/// Interface used to parse, query, manipulate, and serialize JSON.
	/// </summary>
	class IJsonNode
	{
	public:
		/// <summary>
		/// JSON node types.
		/// </summary>
		enum Types
		{
			Object,
			Array,
			String,
			Number,
			Boolean
		};

	public:
		/// <summary>
		/// Deep copy constructor.
		/// </summary>
		/// <param name="other">Node to deep-copy.</param>
		IJsonNode(const IJsonNode& other);

		/// <summary>
		/// Move constructor.
		/// </summary>
		/// <param name="other">Node to move into this one.</param>
		IJsonNode(IJsonNode&& other);

	public:
		/// <summary>
		/// Gets the node type.
		/// </summary>
		/// <returns>Node type.</returns>
		Types GetType() const;

		/// <summary>
		/// Checks whether a child node exists.
		/// </summary>
		/// <param name="key">Child node key.</param>
		/// <returns><c>true</c> if child node exists, <c>false</c> otherwise.</returns>
		bool Exists(const wchar_t* key) const;

		/// <summary>
		/// Sets the value of a child node, creating if necessary.
		/// </summary>
		/// <param name="key">Child node key.</param>
		/// <param name="value">Child node value to copy.</param>
		void SetValue(const wchar_t* key, double value);

		/// <summary>
		/// Sets the value of a child node, creating if necessary.
		/// </summary>
		/// <param name="key">Child node key.</param>
		/// <param name="value">Child node value to copy.</param>
		void SetValue(const wchar_t* key, bool value);

		/// <summary>
		/// Sets the value of a child node, creating if necessary.
		/// </summary>
		/// <param name="key">Child node key.</param>
		/// <param name="value">Child node value to copy.</param>
		void SetValue(const wchar_t* key, int value);

		/// <summary>
		/// Sets the value of a child node, creating if necessary.
		/// </summary>
		/// <param name="key">Child node key.</param>
		/// <param name="value">Child node value to copy.</param>
		void SetValue(const wchar_t* key, JsonString value);

		/// <summary>
		/// Sets the value of a child node, creating if necessary.
		/// </summary>
		/// <param name="key">Child node key.</param>
		/// <param name="value">Child node value to copy.</param>
		void SetValue(const wchar_t* key, const wchar_t* value);

		/// <summary>
		/// Sets the value of a child node, creating if necessary.
		/// </summary>
		/// <param name="key">Child node key.</param>
		/// <param name="value">Child node value to copy.</param>
		void SetValue(const wchar_t* key, const IJsonNode& value);

		/// <summary>
		/// Sets the value of an array item, creating if necessary.
		/// </summary>
		/// <param name="index">Array index.</param>
		/// <param name="value">Child node value to copy.</param>
		void SetValue(unsigned long index, double value);

		/// <summary>
		/// Sets the value of an array item, creating if necessary.
		/// </summary>
		/// <param name="index">Array index.</param>
		/// <param name="value">Child node value to copy.</param>
		void SetValue(unsigned long index, bool value);

		/// <summary>
		/// Sets the value of an array item, creating if necessary.
		/// </summary>
		/// <param name="index">Array index.</param>
		/// <param name="value">Child node value to copy.</param>
		void SetValue(unsigned long index, int value);

		/// <summary>
		/// Sets the value of an array item, creating if necessary.
		/// </summary>
		/// <param name="index">Array index.</param>
		/// <param name="value">Child node value to copy.</param>
		void SetValue(unsigned long index, const wchar_t* value);

		/// <summary>
		/// Sets the value of an array item, creating if necessary.
		/// </summary>
		/// <param name="index">Array index.</param>
		/// <param name="value">Child node value to copy.</param>
		/// <param name="length">Length of child node value to copy.</param>
		void SetValue(unsigned long index, const wchar_t* value, unsigned long length);

		/// <summary>
		/// Sets the value of an array item, creating if necessary.
		/// </summary>
		/// <param name="index">Array index.</param>
		/// <param name="value">Child node value to copy.</param>
		void SetValue(unsigned long index, const IJsonNode& value);

		/// <summary>
		/// Gets a child node.
		/// </summary>
		/// <param name="key">Child node key.</param>
		/// <returns>Child node.</returns>
		/// <remarks>
		/// Throws std::out_of_range if key was not found.
		/// </remarks>
		IJsonNode GetValue(const wchar_t* key);

		/// <summary>
		/// Gets an array node, creating if doesn't exist.
		/// </summary>
		/// <param name="key">Array node key.</param>
		/// <returns>Array node.</returns>
		IJsonNode GetArrayValue(const wchar_t* key);

		/// <summary>
		/// Gets an array item.
		/// </summary>
		/// <param name="index">Array index.</param>
		/// <returns>Array item.</returns>
		/// <remarks>
		/// Throws std::out_of_range if index was not found.
		/// </remarks>
		IJsonNode GetValue(unsigned long index);

		/// <summary>
		/// Gets a child node value as a specific type.
		/// </summary>
		/// <param name="key">Child node key.</param>
		/// <returns>Child node value.</returns>
		/// <remarks>
		/// Throws std::out_of_range if key was not found.
		/// </remarks>
		double GetNumericValue(const wchar_t* key) const;

		/// <summary>
		/// Gets a child node value as a specific type.
		/// </summary>
		/// <param name="key">Child node key.</param>
		/// <returns>Child node value.</returns>
		/// <remarks>
		/// Throws std::out_of_range if key was not found.
		/// </remarks>
		int GetIntegerValue(const wchar_t* key) const;

		/// <summary>
		/// Gets an array item.
		/// </summary>
		/// <param name="index">Array index.</param>
		/// <returns>Array item value.</returns>
		/// <remarks>
		/// Throws std::out_of_range if index was not found.
		/// </remarks>
		double GetNumericValue(unsigned long index) const;

		/// <summary>
		/// Gets an array item.
		/// </summary>
		/// <param name="index">Array index.</param>
		/// <returns>Array item value.</returns>
		/// <remarks>
		/// Throws std::out_of_range if index was not found.
		/// </remarks>
		int GetIntegerValue(unsigned long index) const;

		/// <summary>
		/// Gets a child node value as a specific type.
		/// </summary>
		/// <param name="key">Child node key.</param>
		/// <returns>Child node value.</returns>
		/// <remarks>
		/// Throws std::out_of_range if key was not found.
		/// </remarks>
		bool GetBooleanValue(const wchar_t* key) const;

		/// <summary>
		/// Gets an array item.
		/// </summary>
		/// <param name="index">Array index.</param>
		/// <returns>Array item value.</returns>
		/// <remarks>
		/// Throws std::out_of_range if index was not found.
		/// </remarks>
		bool GetBooleanValue(unsigned long index) const;

		/// <summary>
		/// Gets a child node value as a specific type.
		/// </summary>
		/// <param name="key">Child node key.</param>
		/// <returns>Child node value.</returns>
		/// <remarks>
		/// Throws std::out_of_range if key was not found.
		/// </remarks>
		JsonString GetStringValue(const wchar_t* key) const;

		/// <summary>
		/// Gets an array item.
		/// </summary>
		/// <param name="index">Array index.</param>
		/// <returns>Array item value.</returns>
		/// <remarks>
		/// Throws std::out_of_range if index was not found.
		/// </remarks>
		JsonString GetStringValue(unsigned long index) const;

		/// <summary>
		/// Adds an item to an array.
		/// </summary>
		/// <param name="value">Child node value to copy.</param>
		void Add(const IJsonNode& value);

		/// <summary>
		/// Adds an item to an array.
		/// </summary>
		/// <param name="value">Child node value to copy.</param>
		void Add(double value);

		/// <summary>
		/// Adds an item to an array.
		/// </summary>
		/// <param name="value">Child node value to copy.</param>
		void Add(int value);

		/// <summary>
		/// Adds an item to an array.
		/// </summary>
		/// <param name="value">Child node value to copy.</param>
		void Add(bool value);

		/// <summary>
		/// Adds an item to an array.
		/// </summary>
		/// <param name="value">Child node value to copy.</param>
		void Add(const wchar_t* value);

		/// <summary>
		/// Check whether object or array are empty.
		/// </summary>
		/// <returns><c>true</c> if object or array is empty, <c>false</c> otherwise.</returns>
		bool Empty() const;

		/// <summary>
		/// Gets array item count.
		/// </summary>
		/// <returns>Array item count if node is an array.</returns>
		unsigned long GetCount() const;

		/// <summary>
		/// Clears an array.
		/// </summary>
		void Clear();

		/// <summary>
		/// Serializes to string.
		/// </summary>
		/// <returns>String buffer the node was serialized to.</returns>
		JsonString Serialize() const;

		/// <summary>
		/// Parses from string.
		/// </summary>
		/// <param name="string">String to parse from.</param>
		/// <remarks>
		/// Throws std::invalid_argument if parsing fails.
		/// </remarks>
		void Parse(JsonString string);

	public:
		/// <summary>
		/// Deep copy assignment.
		/// </summary>
		/// <param name="other">Another node to copy.</param>
		/// <returns>Self reference.</returns>
		IJsonNode& operator=(const IJsonNode& other);

		/// <summary>
		/// Move assignment.
		/// </summary>
		/// <param name="other">Another node to move.</param>
		/// <returns>Self reference.</returns>
		IJsonNode& operator=(IJsonNode&& other);

	protected:
		/// <summary>
		/// Default constructor (prevents using IJsonNode except as a base class).
		/// </summary>
		IJsonNode() {}
	};

}}}}}